package cn.qidd.keep.manage.controller.system;

import cn.qidd.keep.domain.core.Constants;
import cn.qidd.keep.domain.core.Result;
import cn.qidd.keep.domain.core.dict.EnableStatus;
import cn.qidd.keep.domain.document.QRole;
import cn.qidd.keep.domain.document.Role;
import cn.qidd.keep.domain.document.User;
import cn.qidd.keep.domain.util.MD5;
import cn.qidd.keep.domain.web.BaseController;
import cn.qidd.keep.domain.web.UserVO;
import cn.qidd.keep.manage.model.login.LoginModel;
import cn.qidd.keep.manage.model.system.*;
import cn.qidd.keep.manage.repository.DepartmentRepository;
import cn.qidd.keep.manage.repository.RoleRepository;
import cn.qidd.keep.manage.repository.UserRepository;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.querydsl.core.BooleanBuilder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.util.Date;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.qidd.keep.domain.core.Constants.TOKEN;

/**
 * Created by sun on 2018/5/20.
 */
@RestController
@RequestMapping("/api/user")
@Api(value = "UserController",description = "用户管理")
public class UserController extends BaseController {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private DepartmentRepository departmentRepository;
    @Autowired
    private RoleRepository roleRepository;

    @PostMapping("/createUser")
    @ApiOperation(value = "新增用户", notes = "新增用户")
    public Result<LoginModel> createUser(@ApiIgnore @RequestHeader(TOKEN) String token,
                                         @Validated @RequestBody UserParams userParams) {
        UserVO userVO = getUserByToken(token);
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        User user = new User();
        BeanUtils.copyProperties(userParams, user);
        user.setPassword(passwordEncoder.encode(MD5.MD5Encode(Constants.DEFAULT_PASSWORD)));
        user.setStatus(EnableStatus.ENABLE);
        user.setDepartment(departmentRepository.findById(userParams.getDeptId()).orElseThrow(RuntimeException::new));
        user.setOperatorTime(new Date());
        user.setOperatorName(userVO.getUserName());
        user.setOperatorRealName(userVO.getRealName());
        userRepository.save(user);
        return new Result<>(Result.Status.SUCCESS, "新增成功");
    }

    @PutMapping("/updateUser")
    @ApiOperation(value = "修改用户", notes = "修改用户")
    public Result updateUser(@RequestHeader(TOKEN) String token,
                             @Validated @RequestBody UpdateUserParams params) {
        UserVO userVO = getUserByToken(token);
        User user = userRepository.findById(params.getId()).orElseThrow(RuntimeException::new);
        BeanUtils.copyProperties(params, user);
        user.setStatus(EnableStatus.ENABLE);
        user.setOperatorTime(new Date());
        user.setOperatorName(userVO.getUserName());
        user.setOperatorRealName(userVO.getRealName());
        userRepository.save(user);
        return new Result<>(Result.Status.SUCCESS, "修改成功");
    }

    @GetMapping("/findUserListByPage")
    @ApiOperation(value = "分页查询用户", notes = "分页查询用户")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "integer", paramType = "query",
                    value = "页数 (1..N)"),
            @ApiImplicitParam(name = "pageSize", defaultValue = "10", dataType = "integer", paramType = "query",
                    value = "每页大小"),
            @ApiImplicitParam(name = "sort", dataType = "string", paramType = "query",
                    value = "依据什么排序: 属性名1 asc,属性名2 desc. ")
    })
    public Result<Page<User>> findUserListByPage(@ApiIgnore Pageable pageable, @Validated UserSearchParams params) {
        BooleanBuilder booleanBuilder = params.generateSearchCondition();
        Page<User> all = userRepository.findAll(booleanBuilder, pageable);
        return new Result<>(Result.Status.SUCCESS, all);
    }

    @PostMapping("/assignRoleToUser")
    @ApiOperation(value = "用户分配角色",notes = "用户分配角色")
    public Result assignRoleToUser(@ApiIgnore @RequestHeader(TOKEN) String token,
                                   @Validated @RequestBody AssignRoleParams params) {
        UserVO userVO = getUserByToken(token);
        User mongoUser = userRepository.findById(params.getUserId()).orElseThrow(RuntimeException::new);
        mongoUser.setRoles(Sets.newHashSet(roleRepository.findAllById(params.getRoleIds())));
        mongoUser.setOperatorName(userVO.getUserName());
        mongoUser.setOperatorRealName(userVO.getRealName());
        mongoUser.setOperatorTime(new Date());
        userRepository.save(mongoUser);
        return new Result(Result.Status.SUCCESS, "分配成功");
    }

    @GetMapping("/findAssignRoleList/{userId}")
    @ApiOperation(value = "用户分配角色查询可分配的角色", notes = "用户分配角色查询可分配的角色")
    public Result<Set<AssignListModel>> findAssignRoleList(@PathVariable String userId) {
        Iterable<Role> all = roleRepository.findAll(QRole.role.id.ne(Constants.ADMINISTRATOR_ROLE_ID));
        User mongoUser = userRepository.findById(userId).orElseThrow(RuntimeException::new);
        Set<Role> roles = mongoUser.getRoles();
        Set<AssignListModel> models = Lists.newArrayList(all).stream().map(e -> {
            AssignListModel model = new AssignListModel();
            model.setId(e.getId());
            model.setRoleName(e.getRoleName());
            if (roles.contains(e)) {
                model.setSelected(true);
            }
            return model;
        }).collect(Collectors.toSet());
        return new Result<>(Result.Status.SUCCESS, models);
    }

}
